package com.tuzhi.base.service.impl;

import com.tuzhi.base.function.SFunction;
import com.tuzhi.base.jpa.domain.Pager;
import com.tuzhi.base.jpa.domain.QueryConditionBO;
import com.tuzhi.base.jpa.domain.WhereConditionBO;
import com.tuzhi.base.jpa.enums.QueryTypeEnum;
import com.tuzhi.base.jpa.healper.QueryHelper;
import com.tuzhi.base.jpa.repository.BaseRepo;
import com.tuzhi.base.jpa.repository.CommonSqlRepo;
import com.tuzhi.base.service.BaseService;
import com.tuzhi.common.constants.StatusConstant;
import com.tuzhi.util.ReflectionTzUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.lang.Nullable;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

public abstract class AbsBaseService<T, ID> implements BaseService<T, ID> {

    private static final Logger log = LoggerFactory.getLogger(AbsBaseService.class);

    @Autowired
    protected CommonSqlRepo commonRepo;

    protected abstract BaseRepo getThisRepo();

    @Override
    public T save(T t) {
        return (T) getThisRepo().save(t);
    }

    @Override
    public void delete(T t) {
        getThisRepo().delete(t);
    }

    @Override
    public int delete4Status(ID id) {
        Class c = ReflectionTzUtil.getClassT(this, 0);
        String jpql = "update " + c.getSimpleName() + " set Sysstatus = ?1  where id = ?2";
        return commonRepo.executeJpql(jpql, StatusConstant.DELETE, id);
    }

    @Override
    public void deleteById(ID id) {
        getThisRepo().deleteById(id);
    }

    @Override
    public T findById(ID id) {
        return (T) getThisRepo().findById(id).orElse(null);
    }

    @Override
    public T findOne(WhereConditionBO whereConditionBO) {
        return (T) getThisRepo().findOne(whereConditionBO);
    }

    @Override
    public List<T> findAllByWhereConditionBO(WhereConditionBO whereConditionBO) {
        return getThisRepo().findAll(whereConditionBO);
    }

    @Override
    public Page<T> findPage(PageRequest pageRequest, WhereConditionBO whereConditionBO) {
        return getThisRepo().findPage(pageRequest, whereConditionBO);
    }

    @Override
    public Page<T> findPage(PageRequest pageRequest, T t) {
        return getThisRepo().findAll(Example.of(t), pageRequest);
    }

    @Override
    public Page<T> findPage(PageRequest pageRequest, T t, String orderName, String orderType) {
        pageRequest.withSort(getThisRepo().buildSort(orderName, orderType));
        return getThisRepo().findAll(Example.of(t), pageRequest);
    }

    @Override
    public List<T> findAll(T t) {
        return getThisRepo().findAll(Example.of(t));
    }

    @Override
    public List<T> findAll(T t, String orderName, String orderType) {
        Sort sort = getThisRepo().buildSort(orderName, orderType);
        return getThisRepo().findAll(Example.of(t), sort);
    }

    @Override
    public T findOne(String propertyName, Object propertyValue) {
        List<QueryConditionBO> list = new ArrayList<>();
        QueryConditionBO queryConditionBO = new QueryConditionBO();
        queryConditionBO.setPropertyName(propertyName);
        queryConditionBO.setObjValue(propertyValue);
        queryConditionBO.setQueryTypeEnum(QueryTypeEnum.equal);
        list.add(queryConditionBO);
        return (T) getThisRepo().findOne(list);
    }

    @Override
    public T get(ID pk) {
        Optional<T> optional = getThisRepo().findById(pk);
        if (optional.isPresent()) {
            return optional.get();
        } else {
            return null;
        }
    }

    @Override
    public Pager<T> listPager(Pager<T> pager) {
        if (pager == null) {
            pager = new Pager<>();
        }
        PageRequest pageRequest = PageRequest.of(pager.queryPage(), pager.getSize());
        Page<T> page = findPage(pageRequest, pager.getWhereConditionBO());
        pager.setPage(page.getNumber());
        pager.setTotalNum(page.getTotalElements());
        pager.setData(page.get().collect(Collectors.toList()));
        return pager;
    }

    @Override
    public T getOneUnique(WhereConditionBO whereConditionBO) {
        return (T) getThisRepo().findOne(whereConditionBO.getQueryList());
    }

    @Override
    public T getOneUnique(SFunction<? super T, ?> propertyName, Object propertyValue) {
        QueryHelper.Builder<T> builder = new QueryHelper.Builder<>();
        builder.eq(propertyName, propertyValue);
        return getOneUnique(builder.build().getWhereConditionBO());
    }


    @Override
    public Optional<T> findOne(@Nullable Specification<T> spec) {
        return getThisRepo().findOne(spec);
    }

    @Override
    public List<T> findAll(@Nullable Specification<T> spec) {
        return getThisRepo().findAll(spec);
    }

    @Override
    public Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable) {
        return getThisRepo().findAll(spec, pageable);
    }

    @Override
    public List<T> findAll(@Nullable Specification<T> spec, Sort sort) {
        return getThisRepo().findAll(spec, sort);
    }

    @Override
    public long count(@Nullable Specification<T> spec) {
        return getThisRepo().count(spec);
    }


    @Override
    public T getOneUnique(@Nullable Specification<T> spec) {
        Optional<T> optional = findOne(spec);
        if (optional.isPresent()) {
            return optional.get();
        }
        return null;
    }

    @Override
    public <T1> List<T1> saveAll(List<T1> list, Integer batchSize) {
        return commonRepo.saveAll(list, batchSize);
    }

    @Override
    public <T1> List<T1> updateAll(List<T1> list, Integer batchSize) {
        return commonRepo.updateAll(list, batchSize);
    }

    @Override
    public <T1> List<T1> batchSaveAll(List<T1> list, Integer batchSize) {
        return commonRepo.batchSaveAll(list, batchSize);
    }
}
